6.3 select
select
一般是与goroutine
、channel
一起使用的。
它的主要作用是用来从多个channel
中读取数据。
相当于使用一个goroutine
通过select
来读取多个channel
的数据。
如果所有channel
都没有数据,那么就会阻塞,直到其中一个channel
有数据为止。
如果多个channel
都有数据,那么就会随机从其中一个先读取数据。
本节代码存放目录为 lesson18
select使用
在上一节中我们已经讲到了channel
,接下来我们将演示select
如何使用。代码如下所示:
func main() {
var (
wg sync.WaitGroup
numberChan chan int
numberBufferChan chan int
)
numberChan = make(chan int)
numberBufferChan = make(chan int, 5)
wg.Add(1)
go func() {
defer wg.Done()
for i := 0; i < 10; i++ {
fmt.Printf("写入数据: %d\n", i)
numberChan <- i
time.Sleep(time.Duration(1) * time.Second)
}
close(numberChan)
}()
wg.Add(1)
go func() {
defer wg.Done()
for i := 100; i < 110; i++ {
fmt.Printf("写入数据Buffer: %d\n", i)
numberBufferChan <- i
time.Sleep(time.Duration(1) * time.Second)
}
close(numberBufferChan)
}()
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
case number1, ok := <-numberChan:
if !ok {
numberChan = nil
} else {
fmt.Printf("读取数据: %d\n", number1)
}
case number2, ok := <-numberBufferChan:
if !ok {
numberBufferChan = nil
} else {
fmt.Printf("读取数据Buffer: %d\n", number2)
}
}
if numberChan == nil && numberBufferChan == nil {
break
}
}
}()
wg.Wait()
}
在上面的代码中,我们创建了两个通道,通过两个协程进行通道数据的发送。
之后我们开启了另一个协程,通过select
读取两个通道的数据。
上面的例子演示了select
的常用操作,另外的用法就是我们在学习goroutine
时所使用到的select{}
。
其实select{}
也是利用了自身的这一特点,从而让主线程一直阻塞,直到所有的协程都执行完毕。
小结
select
在日常场景中使用不算多,不过在一些复杂的业务场景中,比如支付场景,使用的还是比较多的。
本节总结如下:
select
用于同时读取多个通道的数据用法与
switch
类似,但是不能在case
里面使用break
,否则整个协程都会退出通道没有数据时会进行阻塞,这时候如果定义了
default
,就会执行default
里面的代码多个通道都有数据时,程序会基于公平性的原则,随机选择一个读取